package com.itzdm.message.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itzdm.client.client.FileClient;
import com.itzdm.client.domain.po.File;
import com.itzdm.common.result.PageResult;
import com.itzdm.message.domain.dto.MessageSendDto;
import com.itzdm.message.domain.po.Message;
import com.itzdm.message.domain.po.UserMessageRelation;
import com.itzdm.message.domain.vo.MessagePageVo;
import com.itzdm.message.mapper.MessageMapper;
import com.itzdm.message.service.IMessageService;
import com.itzdm.message.service.IUserMessageRelationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @作者：张德明
 * @时间：2025/4/13 15:10
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements IMessageService {

    private final IUserMessageRelationService userMessageRelationService;
    private final FileClient fileClient;
    private final RedisTemplate<String, Object> redisTemplate;

    // 定义缓存相关的常量
    private static final String CACHE_UNREAD_COUNT_PREFIX = "message:unread:count:";
    private static final String CACHE_CHAT_MESSAGES_PREFIX = "message:chat:";
    private static final long UNREAD_COUNT_CACHE_TTL = 5; // 5分钟过期
    private static final long CHAT_MESSAGES_CACHE_TTL = 10; // 10分钟过期

    // 未读消息计数器相关常量
    private static final String UNREAD_COUNT_KEY = "message:unread:counter:";

    /**
     * 增加用户未读消息计数
     *
     * @param userId   用户ID
     * @param senderId 发送者ID
     * @return 增加后的未读数
     */
    private Long incrementUnreadCount(Long userId, Long senderId) {
        // 用户总未读消息计数key
        String totalUnreadKey = UNREAD_COUNT_KEY + userId + ":total";
        // 指定发送者的未读消息计数key
        String senderUnreadKey = UNREAD_COUNT_KEY + userId + ":sender:" + senderId;

        // 增加总未读计数
        Long totalCount = redisTemplate.opsForValue().increment(totalUnreadKey);
        // 增加发送者未读计数
        Long senderCount = redisTemplate.opsForValue().increment(senderUnreadKey);

        log.debug("增加未读消息计数 - 用户: {}, 发送者: {}, 当前未读数: {}", userId, senderId, senderCount);

        return senderCount;
    }

    /**
     * 清零用户与指定好友之间的未读消息计数
     *
     * @param userId   用户ID
     * @param friendId 好友ID
     */
    private void clearUnreadCount(Long userId, Long friendId) {
        // 指定发送者的未读消息计数key
        String senderUnreadKey = UNREAD_COUNT_KEY + userId + ":sender:" + friendId;

        // 获取当前未读数
        Object currentCount = redisTemplate.opsForValue().get(senderUnreadKey);
        if (currentCount != null) {
            Long count = Long.parseLong(currentCount.toString());
            if (count > 0) {
                // 用户总未读消息计数key
                String totalUnreadKey = UNREAD_COUNT_KEY + userId + ":total";

                // 从总未读数中减去该好友的未读数
                redisTemplate.opsForValue().decrement(totalUnreadKey, count);

                // 清零该好友的未读数
                redisTemplate.opsForValue().set(senderUnreadKey, 0);

                log.debug("清零未读消息计数 - 用户: {}, 好友: {}, 清零数量: {}", userId, friendId, count);
            }
        }
    }

    /**
     * 获取Redis中的未读消息计数
     *
     * @param userId 用户ID
     * @return 未读消息计数信息
     */
    public Map<String, Object> getUnreadCountFromRedis(Long userId) {
        Map<String, Object> result = new HashMap<>();

        // 获取总未读数
        String totalUnreadKey = UNREAD_COUNT_KEY + userId + ":total";
        Object totalCount = redisTemplate.opsForValue().get(totalUnreadKey);
        result.put("totalUnread", totalCount != null ? Long.parseLong(totalCount.toString()) : 0);

        // 获取好友别未读数
        Map<Long, Long> unreadBySender = new HashMap<>();

        // 获取该用户所有未读计数器的键
        Set<String> keys = redisTemplate.keys(UNREAD_COUNT_KEY + userId + ":sender:*");
        if (keys != null && !keys.isEmpty()) {
            for (String key : keys) {
                // 从键中提取好友ID
                String[] parts = key.split(":");
                Long senderId = Long.parseLong(parts[parts.length - 1]);

                // 获取未读数
                Object count = redisTemplate.opsForValue().get(key);
                if (count != null) {
                    Long unreadCount = Long.parseLong(count.toString());
                    if (unreadCount > 0) {
                        unreadBySender.put(senderId, unreadCount);
                    }
                }
            }
        }

        result.put("unreadBySender", unreadBySender);
        return result;
    }

    /**
     * 修改发送消息方法，实时更新Redis未读计数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Message sendMessage(MessageSendDto messageSendDto, Long userId) {
        // 现有代码保存消息到数据库
        Message message = new Message();
        BeanUtils.copyProperties(messageSendDto, message);
        message.setCreateTime(LocalDateTime.now());
        message.setStatus(0);
        message.setSenderUserId(userId);
        save(message);

        // 为发送者和接收者创建消息关联记录
        UserMessageRelation senderRelation = new UserMessageRelation();
        senderRelation.setUserId(userId);
        senderRelation.setMessageId(message.getId());
        senderRelation.setIsDeleted(0);
        senderRelation.setCreateTime(LocalDateTime.now());
        userMessageRelationService.save(senderRelation);

        UserMessageRelation receiverRelation = new UserMessageRelation();
        receiverRelation.setUserId(message.getReceiverUserId());
        receiverRelation.setMessageId(message.getId());
        receiverRelation.setIsDeleted(0);
        receiverRelation.setCreateTime(LocalDateTime.now());
        userMessageRelationService.save(receiverRelation);

        // 增加接收者的未读消息计数
        incrementUnreadCount(message.getReceiverUserId(), userId);

        // 清除缓存
        String receiverUnreadKey = CACHE_UNREAD_COUNT_PREFIX + message.getReceiverUserId();
        redisTemplate.delete(receiverUnreadKey);

        // 清除聊天记录缓存
        String chatCacheKeyPattern = CACHE_CHAT_MESSAGES_PREFIX + userId + ":" + message.getReceiverUserId() + "*";
        String reverseChatCacheKeyPattern = CACHE_CHAT_MESSAGES_PREFIX + message.getReceiverUserId() + ":" + userId + "*";

        Set<String> chatCacheKeys = redisTemplate.keys(chatCacheKeyPattern);
        if (chatCacheKeys != null && !chatCacheKeys.isEmpty()) {
            redisTemplate.delete(chatCacheKeys);
            log.debug("发送消息后已清除聊天记录缓存: {}", chatCacheKeyPattern);
        }

        Set<String> reverseChatCacheKeys = redisTemplate.keys(reverseChatCacheKeyPattern);
        if (reverseChatCacheKeys != null && !reverseChatCacheKeys.isEmpty()) {
            redisTemplate.delete(reverseChatCacheKeys);
            log.debug("发送消息后已清除聊天记录缓存: {}", reverseChatCacheKeyPattern);
        }

        return message;
    }

    /**
     * 修改标记已读方法，清零Redis未读计数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markMessagesAsRead(Long userId, Long friendId) {
        // 执行数据库更新
        LambdaUpdateWrapper<Message> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Message::getReceiverUserId, userId)
                .eq(Message::getSenderUserId, friendId)
                .eq(Message::getStatus, 0)
                .set(Message::getStatus, 1);

        boolean updated = update(updateWrapper);

        if (updated) {
            log.info("已将用户{}发送给用户{}的所有未读消息标记为已读", friendId, userId);

            // 清零Redis中的未读计数
            clearUnreadCount(userId, friendId);

            // 清除未读消息数缓存
            String cacheKey = CACHE_UNREAD_COUNT_PREFIX + userId;
            redisTemplate.delete(cacheKey);
            log.debug("已清除未读消息缓存: {}", cacheKey);

            // 清除聊天记录缓存
            String chatCacheKey = CACHE_CHAT_MESSAGES_PREFIX + userId + ":" + friendId;
            redisTemplate.delete(chatCacheKey);
            log.debug("已清除聊天记录缓存: {}", chatCacheKey);
        }
    }

    /**
     * 获取用户所有好友的未读消息数量
     * 优先从Redis获取未读计数
     */
    @Override
    public Map<String, Object> getUnreadMessageCount(Long userId) {
        // 先从Redis获取未读计数
        Map<String, Object> redisResult = getUnreadCountFromRedis(userId);

        // 如果Redis中有数据，直接返回
        Long totalUnread = (Long) redisResult.get("totalUnread");
        if (totalUnread > 0) {
            log.debug("从Redis获取未读消息计数 - 用户: {}, 总未读数: {}", userId, totalUnread);
            return redisResult;
        }

        // Redis中没有数据，则从数据库查询
        log.debug("Redis中无未读计数，从数据库查询 - 用户: {}", userId);

        // 查询数据库并同步到Redis
        Map<String, Object> result = new HashMap<>();

        // 查询总未读数
        LambdaQueryWrapper<Message> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Message::getReceiverUserId, userId)
                .eq(Message::getStatus, 0);
        long count = this.count(queryWrapper);
        result.put("totalUnread", count);

        // 设置Redis总未读数
        if (count > 0) {
            String totalUnreadKey = UNREAD_COUNT_KEY + userId + ":total";
            redisTemplate.opsForValue().set(totalUnreadKey, count);
        }

        // 查询每个发送者的未读数
        QueryWrapper<Message> senderQueryWrapper = new QueryWrapper<>();
        senderQueryWrapper.select("sender_user_id as senderId", "count(*) as count")
                .lambda()
                .eq(Message::getReceiverUserId, userId)
                .eq(Message::getStatus, 0)
                .groupBy(Message::getSenderUserId);

        List<Map<String, Object>> maps = this.getBaseMapper().selectMaps(senderQueryWrapper);

        Map<Long, Long> unreadBySender = new HashMap<>();
        for (Map<String, Object> stat : maps) {
            Long senderId = ((Number) stat.get("senderId")).longValue();
            Long countSender = ((Number) stat.get("count")).longValue();
            unreadBySender.put(senderId, countSender);

            // 设置Redis中每个发送者的未读数
            String senderUnreadKey = UNREAD_COUNT_KEY + userId + ":sender:" + senderId;
            redisTemplate.opsForValue().set(senderUnreadKey, countSender);
        }

        result.put("unreadBySender", unreadBySender);

        // 将结果缓存
        String cacheKey = CACHE_UNREAD_COUNT_PREFIX + userId;
        redisTemplate.opsForValue().set(cacheKey, result, UNREAD_COUNT_CACHE_TTL, TimeUnit.MINUTES);

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMessage(Long userId, Long friendId) {
        // 1. 首先查询用户与好友之间的所有消息ID
        LambdaQueryWrapper<Message> messageQueryWrapper = new LambdaQueryWrapper<>();
        messageQueryWrapper.and(wrapper -> wrapper
                .and(w -> w.eq(Message::getSenderUserId, userId).eq(Message::getReceiverUserId, friendId))
                .or(w -> w.eq(Message::getSenderUserId, friendId).eq(Message::getReceiverUserId, userId))
        );

        // 获取所有相关消息的ID
        List<Message> messages = list(messageQueryWrapper);
        if (messages.isEmpty()) {
            return; // 如果没有消息，直接返回
        }

        List<Long> messageIds = messages.stream()
                .map(Message::getId)
                .collect(Collectors.toList());

        // 2. 从用户消息关联表中直接删除对应记录
        LambdaQueryWrapper<UserMessageRelation> relationQueryWrapper = new LambdaQueryWrapper<>();
        relationQueryWrapper.eq(UserMessageRelation::getUserId, userId)
                .in(UserMessageRelation::getMessageId, messageIds);

        userMessageRelationService.remove(relationQueryWrapper);

        // 清除聊天记录缓存
        String chatCacheKeyPattern = CACHE_CHAT_MESSAGES_PREFIX + userId + ":" + friendId + "*";
        String reverseChatCacheKeyPattern = CACHE_CHAT_MESSAGES_PREFIX + friendId + ":" + userId + "*";

        // 获取所有匹配的键
        Set<String> chatCacheKeys = redisTemplate.keys(chatCacheKeyPattern);
        if (chatCacheKeys != null && !chatCacheKeys.isEmpty()) {
            redisTemplate.delete(chatCacheKeys);
            log.debug("已清除聊天记录缓存: {}", chatCacheKeyPattern);
        }

        Set<String> reverseChatCacheKeys = redisTemplate.keys(reverseChatCacheKeyPattern);
        if (reverseChatCacheKeys != null && !reverseChatCacheKeys.isEmpty()) {
            redisTemplate.delete(reverseChatCacheKeys);
            log.debug("已清除聊天记录缓存: {}", reverseChatCacheKeyPattern);
        }
    }


    @Override
    public PageResult getChatMessagesByUserRelation(Page<Message> page, Long userId, Long friendId) {
        // 构建缓存键
        String cacheKey = CACHE_CHAT_MESSAGES_PREFIX + userId + ":" + friendId
                + ":page" + page.getCurrent() + ":size" + page.getSize();

        // 尝试从缓存获取
        PageResult cachedResult = (PageResult) redisTemplate.opsForValue().get(cacheKey);
        if (cachedResult != null) {
            log.debug("从缓存获取聊天记录: {}", cacheKey);
            return cachedResult;
        }

        log.debug("缓存未命中，从数据库查询聊天记录: {}", cacheKey);

        // 执行原有查询逻辑
        IPage<Message> messageIPage = baseMapper.selectChatMessages(page, userId, friendId);
        if (messageIPage.getRecords().isEmpty()) {
            return new PageResult(messageIPage.getTotal(), Collections.emptyList());
        }

        // 获取文件信息
        Map<Long, File> fileMap = getFileMap(messageIPage.getRecords());

        // 转换为VO对象
        List<MessagePageVo> messageVoList = convertToVoList(messageIPage.getRecords(), fileMap);

        // 创建结果
        PageResult result = new PageResult(messageIPage.getTotal(), messageVoList);

        // 缓存结果
        redisTemplate.opsForValue().set(cacheKey, result, CHAT_MESSAGES_CACHE_TTL, TimeUnit.MINUTES);
        log.debug("聊天记录已缓存: {}", cacheKey);

        return result;
    }

    private Map<Long, File> getFileMap(List<Message> messages) {
        List<Long> fileIds = messages.stream()
                .map(Message::getFileId)
                .filter(Objects::nonNull)
                .distinct()
                .toList();

        if (fileIds.isEmpty()) {
            return Collections.emptyMap();
        }

        List<File> files = fileClient.getFileByIds(fileIds);
        return files.stream()
                .collect(Collectors.toMap(
                        File::getId,
                        Function.identity(),
                        (a, b) -> a,
                        HashMap::new
                ));
    }

    private List<MessagePageVo> convertToVoList(List<Message> messages, Map<Long, File> fileMap) {
        return messages.stream()
                .map(message -> buildMessageVo(message, fileMap))
                .collect(Collectors.toList());
    }

    private MessagePageVo buildMessageVo(Message message, Map<Long, File> fileMap) {
        MessagePageVo vo = new MessagePageVo();
        // 复制基本属性
        BeanUtils.copyProperties(message, vo);

        // 设置文件相关属性
        Long fileId = message.getFileId();
        if (fileId != null && fileMap.containsKey(fileId)) {
            File file = fileMap.get(fileId);
            vo.setFileName(file.getName());
            vo.setFilePath(file.getPath());
            vo.setFileSize(file.getSize());
            vo.setExpireTime(file.getExpireTime());
        }

        return vo;
    }
}
